/*
 * Copyright 2018 The JA-SIG Collaborative. All rights reserved.
 * distributed with thi file and available online at
 */
package com.lap.scp.admin.config;

import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

import com.lap.scp.admin.ao.ResourcesAO;
import com.lap.scp.admin.utils.ShiroUtils;

/**
 * <pre>
 * 启动shiro配置,这里主要包括功能:
 * 1、启动shiro标签
 * 2、加载拦截器
 * 3、注册拦截器
 * 4、加载授权
 * 5、注册授权
 * </pre>
 * 
 * @author 劳水生 Exp
 * @Date 2018年1月23日 下午3:53:12
 * @since 1.0
 */
@Configuration
public class ShiroConfig {

	@Resource
	private ResourcesAO resourcesAO;

	/**
	 * <pre>
	 * 注册 shiroFilter到拦截器代理里面
	 * </pre>
	 * 
	 * @return
	 */
	@Bean
	public FilterRegistrationBean delegatingFilterProxy() {
		FilterRegistrationBean fr = new FilterRegistrationBean();

		DelegatingFilterProxy proxy = new DelegatingFilterProxy();
		proxy.setTargetFilterLifecycle(true);
		proxy.setTargetBeanName("shiroFilter");

		fr.setFilter(proxy);
		return fr;
	}

	/**
	 * <pre>
	 * 启动拦截器类，需要一个SecurityManager。
	 * 1、需要设置一些资源访问权限，比如：静态资源是不需要权限访问，动态地址访问授权
	 * 2、权限认证的格式 perms['地址']
	 * </pre>
	 * 
	 * @param manager
	 * @param resourcesAO
	 * @return
	 */
	@Bean("shiroFilter")
	public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) {
		ShiroFilterFactoryBean sffb = new ShiroFilterFactoryBean();
		sffb.setSecurityManager(manager);
		sffb.setLoginUrl("/login.html");
		sffb.setSuccessUrl("/html/layout.html");
		sffb.setUnauthorizedUrl("/html/401.html");

		List<String> resourcesList = resourcesAO.queryUrlList();
		Map<String, String> ocs = ShiroUtils.initMap(resourcesList);

		sffb.setFilterChainDefinitionMap(ocs);
		return sffb;
	}

	/**
	 * <pre>
	 * 加载授权管理，并把定义的权限登录器赋值
	 * </pre>
	 * 
	 * @param authRealm
	 * @return
	 */
	@Bean(name = "securityManager")
	public SecurityManager securityManager(@Qualifier("adminAuthRealm") AdminAuthRealm authRealm) {
		DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
		manager.setRealm(authRealm);
		manager.setCacheManager(new MemoryConstrainedCacheManager());
		
		Cookie sessionIdCookie = new SimpleCookie();
		sessionIdCookie.setName("meta.session.id");
		
		DefaultWebSessionManager sess= new DefaultWebSessionManager();
		sess.setSessionIdCookie(sessionIdCookie);
		
		manager.setSessionManager(sess);
		return manager;
	}

	/**
	 * <pre>
	 * 配置自定义的权限登录器，并赋值自定义密码加密器
	 * </pre>
	 * 
	 * @param matcher
	 * @return
	 */
	@Bean(name = "adminAuthRealm")
	public AdminAuthRealm authRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) {
		AdminAuthRealm authRealm = new AdminAuthRealm();
		authRealm.setCredentialsMatcher(matcher);
		return authRealm;
	}

	/**
	 * <pre>
	 * 配置自定义的密码比较器，因为每个企业的密码加密方式都不一样，所以这里需要重新定义该类，并把该类进行自动加载定义
	 * </pre>
	 * 
	 * @return
	 */
	@Bean(name = "credentialsMatcher")
	public CredentialsMatcher credentialsMatcher() {
		return new CredentialsMatcher();
	}

	/**
	 * <pre>
	 * 使用静态，防止跟@Value 注解冲突
	 * </pre>
	 * 
	 * @return
	 */
	@Bean
	public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	@Bean
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
		creator.setProxyTargetClass(true);
		return creator;
	}

	@Bean
	public AuthorizationAttributeSourceAdvisor aasa(@Qualifier("securityManager") SecurityManager manager) {
		AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
		advisor.setSecurityManager(manager);
		return advisor;
	}

}
